home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / utilitys / beav_132 / part05 / file.c next >
C/C++ Source or Header  |  1991-11-13  |  19KB  |  787 lines

  1. /*
  2. *  File commands.
  3. */
  4. #include    <sys/types.h> 
  5. #include    <fcntl.h> 
  6. #include    <sys/stat.h> 
  7. #include        "def.h"
  8.  
  9. char    load_file ();
  10. char    readin ();
  11. void    makename ();
  12. bool    writeout ();
  13. bool    parse_f_name ();
  14. A32    ffseek ();
  15.  
  16. extern    char    MSG_rd_file[];
  17. extern    char    MSG_trash[];
  18. extern    char    MSG_ins_file[];
  19. extern    char    MSG_not_fnd[];
  20. extern    char    MSG_visit[];
  21. extern    char    MSG_view[];
  22. extern    char    MSG_buf_ex[];
  23. extern    char    MSG_old_buf[];
  24. extern    char    MSG_buf_nam[];
  25. extern    char    MSG_cnt_cr[];
  26. extern    char    MSG_reading[];
  27. extern    char    MSG_read_lx[];
  28. extern    char    MSG_no_mem_rd[];
  29. extern    char    MSG_wr_file[];
  30. extern    char    MSG_no_fn[];
  31. extern    char    MSG_bk_err[];
  32. extern    char    MSG_writing[];
  33. extern    char    MSG_wrot_n[];
  34. extern    char    MSG_fil_nam[];
  35. extern    char    MSG_null[];
  36. extern    char    ERR_parse_fn[];
  37. extern    char    ERR_addr_neg[];
  38. extern    char    ERR_f_size[];
  39.  
  40. static int  ughlyflag = FALSE;
  41.  
  42. /*
  43. * Read a file into the current
  44. * buffer. This is really easy; all you do it
  45. * find the name of the file, and call the standard
  46. * "read a file into the current buffer" code.
  47. */
  48. char    fileread ()
  49. {
  50.     register char   s;
  51.     char    fname[NFILEN];
  52.     A32     start, end;
  53.  
  54.     if ((s = ereply (MSG_rd_file, fname, NFILEN, NULL)) != TRUE)
  55.         return (s);
  56.     if (parse_f_name (fname, &start, &end))
  57.     {
  58.         adjustcase (fname);
  59.         return (readin (fname, start, end));
  60.     }
  61.     return (TRUE);
  62. }
  63.  
  64.  
  65. /* insert file into current buffer - use readin, and yank
  66. */
  67. char    fileinsert ()
  68. {
  69.     register char   s;
  70.     char    bname[NBUFN],
  71.     fname[NFILEN];
  72.     A32     start, end;
  73.     register char  *trash = MSG_trash;
  74.  
  75.     strcpy (bname, curbp -> b_bname);/* save current buffer */
  76.     if ((s = _usebuffer (trash)) == 0)/* temp buffer */
  77.         return (s);
  78.     if ((s = ereply (MSG_ins_file, fname, NFILEN, NULL)) != TRUE)
  79.         return (s);
  80.     /* if file name and starting and ending addresses are good */
  81.     if (parse_f_name (fname, &start, &end))
  82.     {
  83.         adjustcase (fname);
  84.         if ((s = readin (fname, start, end)) == 0)
  85.         {
  86.             writ_echo (MSG_not_fnd);
  87.             _usebuffer (bname);
  88.             _killbuffer (trash);
  89.             return (s);
  90.         }
  91.         if ((s = _usebuffer (bname)) == 0)
  92.         {
  93.             _killbuffer (trash);
  94.             return (s);
  95.         }
  96.         if ((s = _yankbuffer (trash)) == 0)
  97.         {
  98.             _killbuffer (trash);
  99.             return (s);
  100.         }
  101.         writ_echo (okmsg);
  102.     }
  103.     else
  104.     {
  105.         _usebuffer (bname);
  106.         _killbuffer (trash);
  107.         return (FALSE);
  108.     }
  109.     if ((s = _killbuffer (trash)) == 0)
  110.         return (s);
  111.     wind_on_dot (curwp);
  112.     return (s);
  113. }
  114.  
  115.  
  116. /*
  117. * Select a file for editing.
  118. * Look around to see if you can find the
  119. * fine in another buffer; if you can find it
  120. * just switch to the buffer. If you cannot find
  121. * the file, create a new buffer, read in the
  122. * text, and switch to the new buffer.
  123. *
  124. * also various hacked versions for auto load, and 
  125. * file-vist with auto window split, and readonly (view-file) (jam)
  126. */
  127. char    file_visit (f, n, k)
  128. {
  129.     char    fname[NFILEN];
  130.     char    s;
  131.     A32     start, end;
  132.     if ((s = ereply (MSG_visit, fname, NFILEN, NULL)) != TRUE)
  133.         return (s);
  134.     if (!parse_f_name (fname, &start, &end))
  135.         return (FALSE);
  136.  
  137.     splitwind ();
  138.     return (load_file (fname, start, end));
  139. }
  140.  
  141.  
  142. /* like filevisit, only read only
  143. */
  144. char    viewfile ()
  145. {
  146.     char    fname[NFILEN];
  147.     char    s;
  148.     A32     start, end;
  149.  
  150.     if ((s = ereply (MSG_view, fname, NFILEN, NULL)) != TRUE)
  151.         return (s);
  152.     ughlyflag = TRUE;
  153.     if (!parse_f_name (fname, &start, &end))
  154.         return (FALSE);
  155.  
  156.     s = load_file (fname, start, end);
  157.     if (s)
  158.         curbp -> b_flag |= BFVIEW;
  159.     ughlyflag = FALSE;
  160.     return (s);
  161. }
  162.  
  163.  
  164. char    filevisit ()
  165. {
  166.     char    fname[NFILEN];
  167.     char    s;
  168.     A32     start, end;
  169.  
  170.     if ((s = ereply (MSG_visit, fname, NFILEN, NULL)) != TRUE)
  171.         return (s);
  172.     if (!parse_f_name (fname, &start, &end))
  173.         return (FALSE);
  174.  
  175.     return (load_file (fname, start, end));
  176. }
  177.  
  178.  
  179. char    load_file (fname, start, end)       /* jam */
  180. char   *fname;
  181. A32     start, end;
  182. {
  183.     register    BUFFER * bp;
  184.     register    WINDOW * wp;
  185.     register    LINE * lp;
  186.     register int    i;
  187.     char        s;
  188.     char        bname[NBUFN];
  189.     extern int  initial_load;   /* jam */
  190.     static int  append = 0;
  191.  
  192.     adjustcase (fname);
  193.     for (bp = bheadp; bp != NULL; bp = bp -> b_bufp)
  194.     {
  195.         if (strcmp (bp -> b_fname, fname) == 0)
  196.         {
  197.             if (ughlyflag == TRUE)
  198.             {
  199.                 writ_echo (MSG_buf_ex);
  200.                 return (FALSE);
  201.             }
  202.             if (--curbp -> b_nwnd == 0)
  203.             {
  204.                 curbp -> b_type = BTFILE;
  205.                 curbp -> b_dotp = curwp -> w_dotp;
  206.                 curbp -> b_doto = curwp -> w_doto;
  207.                 curbp -> b_unit_offset = curwp -> w_unit_offset;
  208.                 curbp -> b_markp = curwp -> w_markp;
  209.                 curbp -> b_marko = curwp -> w_marko;
  210.             }
  211.             curbp = bp;
  212.             curwp -> w_bufp = bp;
  213.             if (bp -> b_nwnd++ == 0)
  214.             {
  215.                 curwp -> w_dotp = bp -> b_dotp;
  216.                 curwp -> w_doto = bp -> b_doto;
  217.                 curwp -> w_unit_offset = bp -> b_unit_offset;
  218.                 curwp -> w_markp = bp -> b_markp;
  219.                 curwp -> w_marko = bp -> b_marko;
  220.             }
  221.             else
  222.             {
  223.                 wp = wheadp;
  224.                 while (wp != NULL)
  225.                 {
  226.                     if (wp != curwp && wp -> w_bufp == bp)
  227.                     {
  228.                         curwp -> w_dotp = wp -> w_dotp;
  229.                         curwp -> w_doto = wp -> w_doto;
  230.                         curwp -> w_unit_offset = wp -> w_unit_offset;
  231.                         curwp -> w_markp = wp -> w_markp;
  232.                         curwp -> w_marko = wp -> w_marko;
  233.                         break;
  234.                     }
  235.                     wp = wp -> w_wndp;
  236.                 }
  237.             }
  238.             lp = curwp -> w_dotp;
  239.             i = curwp -> w_ntrows / 2;
  240.             while (i-- && lback (lp) != curbp -> b_linep)
  241.                 lp = lback (lp);
  242.             curwp -> w_linep = lp;
  243.             curwp -> w_flag |= WFMODE | WFHARD;
  244.             if (kbdmop == NULL)
  245.             {
  246.                 writ_echo (MSG_old_buf);
  247.             }
  248.             return (TRUE);
  249.         }
  250.     }
  251.  
  252.     makename (bname, fname);    /* New buffer name.     */
  253.     while ((bp = bfind (bname, FALSE)) != NULL)
  254.     {
  255.         if (initial_load)       /* patch old name */
  256.         {
  257.             funky_name (bname, append++);
  258.             bp = NULL;
  259.             break;
  260.         }
  261.         s = ereply (MSG_buf_nam, bname, NBUFN, NULL);
  262.         if (s == ABORT)         /* ^G to just quit      */
  263.             return (s);
  264.         if (strcmp (bp -> b_bname, bname) == 0 || s == FALSE)
  265.         {
  266.             /* CR to clobber it     */
  267.             makename (bname, fname);
  268.             break;
  269.         }
  270.     }
  271.     if (bp == NULL && (bp = bfind (bname, TRUE)) == NULL)
  272.     {
  273.         err_echo (MSG_cnt_cr);
  274.         return (FALSE);
  275.     }
  276.     if (--curbp -> b_nwnd == 0)
  277.     {
  278.         /* Undisplay.           */
  279.         curbp -> b_type = BTFILE;
  280.         curbp -> b_dotp = curwp -> w_dotp;
  281.         curbp -> b_doto = curwp -> w_doto;
  282.         curbp -> b_unit_offset = curwp -> w_unit_offset;
  283.         curbp -> b_markp = curwp -> w_markp;
  284.         curbp -> b_marko = curwp -> w_marko;
  285.     }
  286.     curbp = bp;                 /* Switch to it.        */
  287.     curwp -> w_bufp = bp;
  288.     curbp -> b_nwnd++;
  289.     return (readin (fname, start, end));    /* Read it in.          */
  290. }
  291.  
  292.  
  293. /*
  294. * Read the file "fname" into the current buffer.
  295. * Make all of the text in the buffer go away, after checking
  296. * for unsaved changes. This is called by the "read" command, the
  297. * "visit" command, and the mainline (for "beav file"). If the
  298. * BACKUP conditional is set, then this routine also does the read
  299. * end of backup processing. The BFBAK flag, if set in a buffer,
  300. * says that a backup should be taken. It is set when a file is
  301. * read in, but not on a new file (you don't need to make a backup
  302. * copy of nothing). Return a standard status. Print a summary
  303. * (lines read, error message) out as well.
  304. */
  305. char    readin (fname, start, end)
  306. char    fname[];
  307. A32     start, end;
  308. {
  309.     register    LINE * lp1;
  310.     register    LINE * lp2;
  311.     register    WINDOW * wp;
  312.     register    BUFFER * bp;
  313.     register    char   s, m;
  314.     long        byte_cnt;
  315.     LPOS        req_chars;
  316.     char        buf[NCOL], buf1[NCOL];
  317.     A32         temp;
  318.  
  319.     m = TRUE;
  320.     byte_cnt = 0;
  321.     bp = curbp;                 /* Cheap.               */
  322.     if ((s = bclear (bp)) != TRUE)/* Might be old.        */
  323.         return (s);
  324. #if     BACKUP
  325.     bp -> b_flag &= ~(BFCHG | BFBAK);/* No change, backup.   */
  326. #else
  327.     bp -> b_flag &= ~BFCHG;     /* No change.           */
  328. #endif
  329.     if ((start == 0L) && (end == MAXPOS))
  330.         strcpy (bp -> b_fname, fname);
  331.     else
  332.         strcpy (bp -> b_fname, MSG_null);
  333.     bp -> b_file_size = 0;
  334.     bp -> b_type = BTFILE;
  335.     if ((s = ffropen (fname)) == FIOERR || s == FIOFNF)/* jam */
  336.         goto out;
  337.     bp -> b_file_size = file_len ();  /* get the file lenth */
  338.     sprintf (buf, MSG_reading, fname);/* jam */
  339.     writ_echo (buf);
  340.     temp = ffseek (start);
  341.     if (temp != start)
  342.     {
  343.         sprintf (buf1, ERR_f_size, R_POS_FMT(curwp));
  344.         sprintf (buf, buf1, temp);
  345.         writ_echo (buf);
  346.         return (FALSE);
  347.     }
  348.     /* only read the requested number of characters */
  349.     if ((end - start) > NLINE)
  350.         req_chars = NLINE;
  351.     else
  352.         req_chars = (int)(end - start);
  353.  
  354.     if ((lp1 = lalloc(req_chars)) == NULL)
  355.     {
  356.         bp -> b_flag |= BFVIEW; /* if no memory set to read only mode */
  357.  
  358.         m = FALSE;          /* flag memory allocation error */
  359.     }
  360.     else
  361.     {
  362.         while ((s = ffgetline (lp1->l_text, lp1->l_size, &lp1->l_used)) == FIOSUC)
  363.         {
  364.             /* this code breaks rules for knowing how lines * are stored and linked
  365.             together, oh well */
  366.             lp2 = lback (curbp -> b_linep);
  367.             lp2 -> l_fp = lp1;
  368.             lp1 -> l_fp = curbp -> b_linep;
  369.             lp1 -> l_bp = lp2;
  370.             curbp -> b_linep -> l_bp = lp1;
  371.             lp1 -> l_file_offset = byte_cnt;   /* file offset from begining */
  372.             byte_cnt += (long) lp1 -> l_used;    /* number of bytes read in    */
  373.             start += (long) lp1 -> l_used;
  374.             if (end <= start)
  375.                 break;
  376.             /* stop reading after the requested number of characters */
  377.             if (end < start + req_chars)
  378.             {
  379.                 req_chars = end - start;
  380.             }
  381.             if ((lp1 = lalloc(req_chars)) == NULL)
  382.             {
  383.                 bp -> b_flag |= BFVIEW; /* if no memory set to read only mode */
  384.  
  385.                 m = FALSE;          /* flag memory allocation error */
  386.                 break;
  387.             }
  388.             if ((byte_cnt & 0x7fff) == 0)
  389.             {
  390.                 sprintf (buf1, MSG_read_lx, R_POS_FMT(curwp));
  391.                 sprintf (buf, buf1, (ulong)byte_cnt);
  392.                 writ_echo (buf);
  393.                 /* check if we should quit */
  394.                 if (ttkeyready ())
  395.                 {
  396.                     wind_on_dot_all();
  397.                     if (ttgetc () == CTL_G)  /* was it an abort key? */
  398.                     {
  399.                         s = FIOERR;
  400.                         break;
  401.                     }
  402.                 }
  403.             }
  404.         }
  405.     }
  406.     ffclose ();                 /* Ignore errors.       */
  407.     if (s == FIOEOF && kbdmop == NULL)
  408.     {
  409.         /* Don't zap an error.   */
  410.         sprintf (buf1, MSG_read_lx, R_POS_FMT(curwp));
  411.         sprintf (buf, buf1, byte_cnt);
  412.         writ_echo (buf);
  413.     }
  414.     if (m == FALSE && kbdmop == NULL)
  415.     {
  416.         /* Don't zap an error.   */
  417.         sprintf (buf, MSG_no_mem_rd);
  418.         err_echo (buf);
  419.     }
  420.  
  421. #if     BACKUP
  422.     curbp -> b_flag |= BFBAK;   /* Need a backup.       */
  423. #endif
  424. out:
  425.     for (wp = wheadp; wp != NULL; wp = wp -> w_wndp)
  426.     {
  427.         if (wp -> w_bufp == curbp)
  428.         {
  429.             wp -> w_linep = lforw (curbp -> b_linep);
  430.             wp -> w_dotp = lforw (curbp -> b_linep);
  431.             wp -> w_doto = 0;
  432.             wp -> w_unit_offset = 0;
  433.             wp -> w_markp = NULL;
  434.             wp -> w_marko = 0;
  435.             wp -> w_flag |= WFMODE | WFHARD;
  436.         }
  437.     }
  438.     /* so tell yank-buffer about it */
  439.     if ((blistp -> b_nwnd != 0) &&  /* update buffer display */
  440.     (blistp -> b_type == BTLIST))
  441.         listbuffers ();
  442.     if (s == FIOERR || s == FIOFNF)/* False if error.      */
  443.         return (FALSE);
  444.     return (TRUE);
  445. }
  446.  
  447.  
  448. /*
  449. * Take a file name, and from it
  450. * fabricate a buffer name. This routine knows
  451. * about the syntax of file names on the target system.
  452. * BDC1         left scan delimiter.
  453. * BDC2         optional second left scan delimiter.
  454. * BDC3         optional right scan delimiter.
  455. */
  456. void makename (bname, fname)
  457. char    bname[];
  458. char    fname[];
  459. {
  460.     register char  *cp1;
  461.     register char  *cp2;
  462.  
  463.     cp1 = &fname[0];
  464.     while (*cp1 != 0)
  465.         ++cp1;
  466. #ifdef  BDC2
  467.     while (cp1 != &fname[0] && cp1[-1] != BDC1 && cp1[-1] != BDC2)
  468.         --cp1;
  469. #else
  470.     while (cp1 != &fname[0] && cp1[-1] != BDC1)
  471.         --cp1;
  472. #endif
  473.     cp2 = &bname[0];
  474. #ifdef  BDC3
  475.     while (cp2 != &bname[NBUFN - 1] && *cp1 != 0 && *cp1 != BDC3)
  476.         *cp2++ = *cp1++;
  477. #else
  478.     while (cp2 != &bname[NBUFN - 1] && *cp1 != 0)
  479.         *cp2++ = *cp1++;
  480. #endif
  481.     *cp2 = 0;
  482. }
  483.  
  484.  
  485. /*
  486. * Ask for a file name, and write the
  487. * contents of the current buffer to that file.
  488. * Update the remembered file name and clear the
  489. * buffer changed flag. This handling of file names
  490. * is different from the earlier versions, and
  491. * is more compatable with Gosling EMACS than
  492. * with ITS EMACS.
  493. */
  494. char    filewrite ()
  495. {
  496.     register    WINDOW * wp;
  497.     register char   s;
  498.     char    fname[NFILEN];
  499.     A32     start, end;
  500.  
  501.     if ((s = ereply (MSG_wr_file, fname, NFILEN, NULL)) != TRUE)
  502.         return (s);
  503.     if (!parse_f_name (fname, &start, &end))
  504.         return (FALSE);
  505.  
  506.     adjustcase (fname);
  507.     if ((s = writeout (fname, start, end, S_IREAD | S_IWRITE)) == TRUE)
  508.     {
  509.         strcpy (curbp -> b_fname, fname);
  510.         curbp -> b_flag &= ~BFCHG;
  511.         wp = wheadp;            /* Update mode lines.   */
  512.         while (wp != NULL)
  513.         {
  514.             if (wp -> w_bufp == curbp)
  515.                 wp -> w_flag |= WFMODE;
  516.             wp = wp -> w_wndp;
  517.         }
  518.     }
  519.  
  520. #if     BACKUP
  521.     curbp -> b_flag &= ~BFBAK;  /* No backup.           */
  522. #endif
  523.     return (s);
  524. }
  525.  
  526.  
  527. /*
  528. * Save the contents of the current buffer back into
  529. * its associated file. Do nothing if there have been no changes
  530. * (is this a bug, or a feature). Error if there is no remembered
  531. * file name. If this is the first write since the read or visit,
  532. * then a backup copy of the file is made.
  533. */
  534. char    filesave ()
  535. {
  536.     register    WINDOW * wp;
  537.     register char   s;
  538.     struct    stat    st;
  539.  
  540.     if ((curbp -> b_flag & BFCHG) == 0)/* Return, no changes.  */
  541.         return (TRUE);
  542.     if (curbp -> b_fname[0] == 0)/* Must have a name.    */
  543.     {
  544.         if (!(curbp -> b_type == BTSAVE))/* yanked buffer */
  545.         {
  546.             writ_echo (MSG_no_fn);
  547.         }
  548.         return (FALSE);
  549.     }
  550.     st.st_mode = S_IREAD | S_IWRITE;    /* set default */
  551. #if     BACKUP
  552.     if ((curbp -> b_flag & BFBAK) != 0)
  553.     {
  554.         /* get the mode of the file */
  555.         stat (curbp -> b_fname, &st);
  556.  
  557.         s = fbackupfile (curbp -> b_fname);
  558.         if (s == ABORT)         /* Hard error.          */
  559.             return (s);
  560.         if (s == FALSE          /* Softer error.        */
  561.         && (s = eyesno (MSG_bk_err)) != TRUE)
  562.             return (s);
  563.     }
  564.  
  565. #endif
  566.     if ((s = writeout (curbp -> b_fname, 0L, MAXPOS, st.st_mode)) == TRUE)
  567.     {
  568.         curbp -> b_flag &= ~BFCHG;/* No change.           */
  569.         curbp -> b_flag &= ~BFBAD;/* if it was trashed, forget it now */
  570.         wp = wheadp;            /* Update mode lines.   */
  571.         while (wp != NULL)
  572.         {
  573.             if (wp -> w_bufp == curbp)
  574.                 wp -> w_flag |= WFMODE;
  575.             wp = wp -> w_wndp;
  576.         }
  577.     }
  578.  
  579. #if     BACKUP
  580.     curbp -> b_flag &= ~BFBAK;  /* No backup.           */
  581. #endif
  582.     return (s);
  583. }
  584.  
  585. /*
  586. * This function performs the details of file
  587. * writing. Uses the file management routines in the
  588. * "fileio.c" package. The number of lines written is
  589. * displayed. Sadly, it looks inside a LINE; provide
  590. * a macro for this. Most of the grief is error
  591. * checking of some sort.
  592. * The file permissions are set as requested.
  593. */
  594. bool writeout (fn, start, end, mode)
  595. char   *fn;
  596. A32     start, end;
  597. ushort    mode;
  598. {
  599.     register    int    s, num_chars;
  600.     register    LINE * lp;
  601.     register    long   nbytes;
  602.     char        buf[NCOL], buf1[NCOL];
  603.     A32         temp;
  604.  
  605.     if ((s = ffwopen (fn, mode)) != FIOSUC)/* Open writes message. */
  606.         return (FALSE);
  607.     temp = ffseek (start);
  608.     if (temp != start)
  609.     {
  610.         sprintf (buf1, ERR_f_size, R_POS_FMT(curwp));
  611.         sprintf (buf, buf1, temp);
  612.         writ_echo (buf);
  613.         return (FALSE);
  614.     }
  615.     sprintf (buf, MSG_writing, fn);/* jam */
  616.     writ_echo (buf);
  617.  
  618.     /* insure that the help screen reflects the latest bindings */
  619.     if (curbp == blistp)
  620.         wallchart (0, 0, 0);
  621.  
  622.     lp = lforw (curbp -> b_linep);/* First line. */
  623.     nbytes = 0;                  /* Number of bytes.  */
  624.     temp = end - start;         /* number of bytes to write */
  625.     while (lp != curbp -> b_linep)
  626.     {
  627.         if (curbp == blistp)
  628.         {
  629.             /* special list buffer */
  630.             num_chars = HENDCOL;    /* limit line length */
  631.             lp -> l_text[num_chars - 1] = '\n';
  632.         }
  633.         else
  634.         {
  635.             /* standard buffer */
  636.             if (nbytes + (long)llength (lp) > temp)
  637.                 num_chars = (int)(temp - nbytes);
  638.             else
  639.                 num_chars = llength (lp);
  640.         }
  641.         if ((s = ffputline (&lp -> l_text[0], num_chars)) != FIOSUC)
  642.             break;
  643.         nbytes += num_chars;
  644.         if (temp <= nbytes)
  645.             break;
  646.         lp = lforw (lp);
  647.  
  648.         if ((nbytes & 0x7fff) == 0)
  649.         {
  650.             sprintf (buf1, MSG_wrot_n, R_POS_FMT(curwp));
  651.             sprintf (buf, buf1, (ulong)nbytes);
  652.             writ_echo (buf);
  653.             /* check if we should quit */
  654.             if (ttkeyready ())
  655.             {
  656.                 wind_on_dot_all();
  657.                 if (ttgetc () == CTL_G)  /* was it an abort key? */
  658.                 {
  659.                     s = FIOERR;
  660.                     break;
  661.                 }
  662.             }
  663.         }
  664.     }
  665.     if (s == FIOSUC)
  666.     {
  667.         /* No write error. */
  668.         s = ffclose ();
  669.         if (s == FIOSUC && kbdmop == NULL)
  670.         {
  671.             sprintf (buf1, MSG_wrot_n, R_POS_FMT(curwp));
  672.             sprintf (buf, buf1, (long) nbytes);
  673.             writ_echo (buf);
  674.         }
  675.     }
  676.     else /* Ignore close error   */
  677.         ffclose ();             /* if a write error.    */
  678.     curbp -> b_file_size = nbytes;  /* update file size */
  679.     if ((blistp -> b_nwnd != 0) &&  /* update buffer display */
  680.     (blistp -> b_type == BTLIST))
  681.         listbuffers ();
  682.     if (s != FIOSUC)            /* Some sort of error.  */
  683.         return (FALSE);
  684.     return (TRUE);
  685. }
  686.  
  687. /*
  688. * The command allows the user
  689. * to modify the file name associated with
  690. * the current buffer. It is like the "f" command
  691. * in UNIX "ed". The operation is simple; just zap
  692. * the name in the BUFFER structure, and mark the windows
  693. * as needing an update. You can type a blank line at the
  694. * prompt if you wish.
  695. */
  696. char    filename ()
  697. {
  698.     register    WINDOW * wp;
  699.     register char   s;
  700.     char    fname[NFILEN];
  701.     A32     start, end;
  702.  
  703.     if ((s = ereply (MSG_fil_nam, fname, NFILEN, NULL)) == ABORT)
  704.         return (s);
  705.     if (!parse_f_name (fname, &start, &end))
  706.         return (FALSE);
  707.  
  708.     adjustcase (fname);
  709.     curbp -> b_flag |= BFCHG;   /* jam - on name change, set modify */
  710.     BUF_START(curwp) = start;
  711.     l_fix_up (curbp -> b_linep -> l_fp); /* adjust file offsets from first line */
  712.     strcpy (curbp -> b_fname, fname);/* Fix name.            */
  713.     wp = wheadp;                /* Update mode lines.   */
  714.     while (wp != NULL)
  715.     {
  716.         if (wp -> w_bufp == curbp)
  717.             wp -> w_flag |= WFMODE;
  718.         wp = wp -> w_wndp;
  719.     }
  720. #if     BACKUP
  721.     curbp -> b_flag &= ~BFBAK;  /* No backup.           */
  722. #endif
  723.     return (TRUE);
  724. }
  725.  
  726. /*
  727. *   Get the length parameters that were entered with the file name.
  728. *   There can be the file name only.
  729. *   There can be a file name and a starting position.
  730. *   There can be a name a starting position and an ending position.
  731. *   There can be a name a starting position and a length.
  732. *
  733. *   input:
  734. *       fn      pointer to file name string to parse.
  735. *
  736. *   output:
  737. *       fn      pointer to null terminated file name.
  738. *       start   pointer to the starting point in file (default = 0)
  739. *       end     pointer to the end point in file (default = -1)
  740. *       return  FALSE if file name or addresses are bad.
  741. */
  742. bool    parse_f_name (fn, start, end)
  743. char    *fn;
  744. A32     *start, *end;
  745. {
  746.     char    buf[NFILEN], buf1[NCOL], fmt[NCOL];
  747.     int     i_cnt;
  748.  
  749.     /* build up format string according to the current screen format */
  750.     sprintf (fmt, "%s %s %s", "%s", R_POS_FMT(curwp), R_POS_FMT(curwp));
  751.  
  752.     *start = 0L;
  753.     *end = MAXPOS;
  754.     sscanf (fn, fmt, buf, start, end);
  755.  
  756.     if (*end != MAXPOS)
  757.     {
  758.         for (i_cnt = strlen (fn) - 1; i_cnt >= 0; i_cnt--)
  759.         {
  760.             if (fn[i_cnt] == '+')
  761.             {
  762.                 *end += *start;
  763.                 break;
  764.             }
  765.         }
  766.     }
  767.     /* start should preceed end */
  768.     if (*start > *end)
  769.     {
  770.         sprintf (buf1, ERR_parse_fn, R_POS_FMT(curwp), R_POS_FMT(curwp));
  771.         sprintf (buf, buf1, *start, *end);
  772.         writ_echo (buf);
  773.         return (FALSE);
  774.     }
  775.  
  776.     /* error if addresses are negative */
  777.     if ((*start < 0) || (*end < 0))
  778.     {
  779.         writ_echo (ERR_addr_neg);
  780.         return (FALSE);
  781.     }
  782.  
  783.     /* deposit null terminated file name */
  784.     strcpy (fn, buf);
  785.     return (TRUE);
  786. }
  787.